package com.wondertek.onvif.service.auth;

import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.net.HttpURLConnection;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.time.Instant;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Base64;

/**
 * WS-Security UsernameToken 认证策略实现
 * 符合ONVIF标准的SOAP Header认证方式
 */
@Slf4j
@Component
public class WsSecurityAuthStrategy implements AuthenticationStrategy {
    
    private static final SecureRandom SECURE_RANDOM = new SecureRandom();
    
    @Override
    public String buildAuthHeader(String username, String password, String serviceUrl, String method) {
        // WS-Security不使用HTTP认证头，而是在SOAP Header中添加Security元素
        // 这里返回null，实际的认证信息将通过buildWsSecurityHeader方法添加到SOAP中
        return null;
    }
    
    /**
     * 构建WS-Security头部
     * 
     * @param username 用户名
     * @param password 密码
     * @return WS-Security头部XML
     */
    public String buildWsSecurityHeader(String username, String password) {
        if (StrUtil.isEmpty(username) || StrUtil.isEmpty(password)) {
            return "";
        }
        
        try {
            // 生成随机Nonce
            byte[] nonceBytes = new byte[16];
            SECURE_RANDOM.nextBytes(nonceBytes);
            String nonce = Base64.getEncoder().encodeToString(nonceBytes);
            
            // 生成当前时间戳
            String created = Instant.now().atOffset(ZoneOffset.UTC)
                .format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"));
            
            // 计算密码摘要: Base64(SHA1(nonce_bytes + created + password))
            // 根据ONVIF标准，摘要计算应该使用原始nonce字节数组，而不是Base64编码后的字符串
            MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
            sha1.update(nonceBytes); // 直接使用nonce字节数组
            sha1.update(created.getBytes(StandardCharsets.UTF_8));
            sha1.update(password.getBytes(StandardCharsets.UTF_8));
            byte[] digestBytes = sha1.digest();
            String passwordDigest = Base64.getEncoder().encodeToString(digestBytes);
            
            // 构建WS-Security头部
            StringBuilder wsSecurityHeader = new StringBuilder();
            wsSecurityHeader.append("<soap:Header>");
            wsSecurityHeader.append("<wsse:Security xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\" ");
            wsSecurityHeader.append("xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\">");
            wsSecurityHeader.append("<wsse:UsernameToken>");
            wsSecurityHeader.append("<wsse:Username>").append(escapeXml(username)).append("</wsse:Username>");
            wsSecurityHeader.append("<wsse:Password Type=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest\">");
            wsSecurityHeader.append(passwordDigest).append("</wsse:Password>");
            wsSecurityHeader.append("<wsse:Nonce EncodingType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary\">");
            wsSecurityHeader.append(nonce).append("</wsse:Nonce>");
            wsSecurityHeader.append("<wsu:Created>").append(created).append("</wsu:Created>");
            wsSecurityHeader.append("</wsse:UsernameToken>");
            wsSecurityHeader.append("</wsse:Security>");
            wsSecurityHeader.append("</soap:Header>");
            
            log.debug("构建WS-Security认证头: username={}, nonce={}, created={}", username, nonce, created);
            return wsSecurityHeader.toString();
            
        } catch (Exception e) {
            log.error("构建WS-Security头部失败", e);
            return "";
        }
    }
    
    /**
     * XML转义
     */
    private String escapeXml(String text) {
        if (text == null) {
            return "";
        }
        return text.replace("&", "&amp;")
                  .replace("<", "&lt;")
                  .replace(">", "&gt;")
                  .replace("\"", "&quot;")
                  .replace("'", "&apos;");
    }
    
    @Override
    public boolean isSupported(HttpURLConnection connection) {
        // WS-Security是ONVIF标准认证方式，优先支持
        return true;
    }
    
    @Override
    public String getAuthType() {
        return "WS-Security";
    }
    
    @Override
    public int getPriority() {
        return 1; // 最高优先级，符合ONVIF标准
    }
}